Keygen Tutorial 1
				   Yes123 '99
---[ WARNING ]--------------------------------------------------------------------------------

This Tutorial is for education purpose only. I wrote it to allow you to understand how are
coded some protections schemes in software. I didn't make it to allow you to use the target
program without paying the author. If you plan to use these programs regularly, please remeber
to send your $ to the authors, don't be a outlaw, and over all, don't be a LAMER !!!

---[ INTRO ]----------------------------------------------------------------------------------

target: A Day in the Life v1.0
where : http://www.cartoonlogic.com

Tools : SoftIce for Win9x v3.24
	W32Dasm v8.9
        Programming Language (C, Pascal, asm, anyone you want, I'll use our old C)

This is my first tutorial in english. I hope my bad spelling won't make this text 
too much hard to understand for you. :)

I'll try to teach you how to make a key generator for a program. The way i teach will be 
based more on reverse enginerring (instead of only cracking the program, we try to fully 
understand the whole key-generating algorithm), some newbies maybe having problem of 
reading this.

I'll assume you know the following:

- basic use of SoftIce
- asm instructions (at least the ones used for cracking)
---[ TUTORIAL ]-------------------------------------------------------------------------------

At first, launch SoftIce (assuming you know the basics, and how to setup this Numega's
nice tool). Then launch our target, ADITL1.0.exe! Go to the help menu and select the register.

Well, we'll try to find how this protection is running. Let's enter anything as a name
and random digits as a serial. Don't click the OK button yet, but hit CTRL & D to bring up 
SoftICe. We'll define a breakpoint, using the classical BPX hmemcpy(it works for most program.) 
Hit CTRL-D again to go back to the program. Click OK and... SoftICe pop up.

Keep pressing F12 until you get back to the traget program code. Trace a few lines down you will
be in:


:004848A7 E8D4B1F9FF              call 0041FA80			;start here
:004848AC 8B45F8                  mov eax, dword ptr [ebp-08]	;eax=pointer to name
:004848AF E8C4F3F7FF              call 00403C78			;return eax=length of name
:004848B4 8BF0                    mov esi, eax			;esi=length of name
:004848B6 85F6                    test esi, esi			;test length
:004848B8 7E28                    jle 004848E2			;if no name enterthen jump
:004848BA B901000000              mov ecx, 00000001		;counter=1;ebx=1 firstly

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004848E0(C)

*first important loop*
======================
:004848BF 8B45F8                  mov eax, dword ptr [ebp-08]	;move name to eax
:004848C2 0FB67C08FF              movzx edi, byte ptr [eax+ecx-01];edi=name[ecx]
:004848C7 0FAFFB                  imul edi, ebx			;edi=edi*ebx
:004848CA 83FF12                  cmp edi, 00000012		;compare edi with 0x12
:004848CD 7C0F                    jl 004848DE			;jump if less than
:004848CF 8B45F8                  mov eax, dword ptr [ebp-08]	;move name to eax
:004848D2 8BC7                    mov eax, edi			;eax=edi
:004848D4 BB11000000              mov ebx, 00000011		;ebx=11
:004848D9 99                      cdq				;expand eax
:004848DA F7FB                    idiv ebx			;eax=eax/11
:004848DC 8BD8                    mov ebx, eax			;ebx=eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004848CD(C)
|
:004848DE 41                      inc ecx
:004848DF 4E                      dec esi
:004848E0 75DD                    jne 004848BF			;if unfinish loop back

The above code is the first important loop of the key-genereating loop.It is basicaaly a very
simple coding and can be summurized as follow:
code=name[ecx]*code/17
Ecx act as a counter, it count the current byte of name in increasing order, and the ebx is 
the code we want.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004848B8(C)
|
:004848E2 8B45F8                  mov eax, dword ptr [ebp-08]	;move name to eax
:004848E5 E88EF3F7FF              call 00403C78			;calculate length of eax
:004848EA 8BC8                    mov ecx, eax
:004848EC 83F901                  cmp ecx, 00000001
:004848EF 7C30                    jl 00484921			;jump if no name enter 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048491F(C)

*second important loop*
=======================
:004848F1 8B45F8                  mov eax, dword ptr [ebp-08]	;move name to eax
:004848F4 0FB67408FF              movzx esi, byte ptr [eax+ecx-01];move name[ecx] to esi
:004848F9 8BC1                    mov eax, ecx			;ecx is in decresing order
:004848FB 99                      cdq				;clear edx
:004848FC F7FE                    idiv esi			;eax = count / name[ecx]
:004848FE 85D2                    test edx, edx			;test if any number remain
:00484900 740D                    je 0048490F			;if no then jump
:00484902 8B45F8                  mov eax, dword ptr [ebp-08]	;eax=name
:00484905 83EE0B                  sub esi, 0000000B		;name[ecx]=name[ecx]-0B
:00484908 0FAFF3                  imul esi, ebx			;code=esi*code
:0048490B 8BDE                    mov ebx, esi			;ebx=code
:0048490D EB0D                    jmp 0048491C			;unconditional jump

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00484900(C)
|
:0048490F 8B45F8                  mov eax, dword ptr [ebp-08]	;eax=name
:00484912 83C611                  add esi, 00000011		;name[0]=name[0]+0x11
:00484915 8BC3                    mov eax, ebx			;eax=code
:00484917 99                      cdq				;clear edx
:00484918 F7FE                    idiv esi			;eax=eax/esi
:0048491A 8BD8                    mov ebx, eax			;ebx=code

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048490D(U)
|
:0048491C 49                      dec ecx
:0048491D 85C9                    test ecx, ecx
:0048491F 75D0                    jne 004848F1			;loop if unfinish

The second important loop is also quite simple, we can neglect line 48490F to 48491A because 
it will never reach when is came to last byte, it will pass throught 48491F and never have 
change to loop back. So the testing algorithem from 4848FB to 484900 actually is rubbish code.
This might be a bug or something that make to confuse us.
The above coding can be summerized as:
code=code*(name[ecx]-0x0b)	;code in this case is our serial calculated
Ecx is a counter in decreasing order, it start it the last byte of our name. Ebx is the code we
want.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004848EF(C)
|
:00484921 8B45F8                  mov eax, dword ptr [ebp-08]	
:00484924 E84FF3F7FF              call 00403C78
:00484929 50                      push eax
:0048492A 8BC3                    mov eax, ebx
:0048492C 5A                      pop edx			;edx=length of name
:0048492D 2BC2                    sub eax, edx			;code=code-length
:0048492F B907000000              mov ecx, 00000007		;ecx=0x07
:00484934 99                      cdq
:00484935 F7F9                    idiv ecx			;code=code/7
:00484937 05920F0000              add eax, 00000F92		;code=code+0x0f92
:0048493C 8BD8                    mov ebx, eax			;ebx=code

Until here our code=((code-length of our name)/7)+0F92

:0048493E 8D55F4                  lea edx, dword ptr [ebp-0C]	;edx=location [final reg key]
:00484941 8BC3                    mov eax, ebx			;eax=code
:00484943 E8042BF8FF              call 0040744C			;This call convert the int format
:00484948 8D45F0                  lea eax, dword ptr [ebp-10]	;of the code into character,
:0048494B 8B55F8                  mov edx, dword ptr [ebp-08]	;including it's sign also
:0048494E 8A12                    mov dl, byte ptr [edx]

The call at 484943 actually convert our code into string form including sign also.

:00484950 E84BF2F7FF              call 00403BA0

This call search for the char need to be insert in first byte of our serial, it return the
in [ebp-10]. In this case is search for the first byte of our name as result.

:00484955 8B45F0                  mov eax, dword ptr [ebp-10]	;eax=target of insertion
:00484958 8D55F4                  lea edx, dword ptr [ebp-0C]	;edx=target for insertion
:0048495B B901000000              mov ecx, 00000001		;ecx=location
:00484960 E89FF5F7FF              call 00403F04			;This call insert first char 
:00484965 8B55F8                  mov edx, dword ptr [ebp-08]	;of name into first location
:00484968 B8744A4800              mov eax, 00484A74		;of code

The call 00403F04 actually is a call to insert certain character into the string. It need
EAX for what we want to insert, in above case it need to insert the first char of name.
EDX is the address for the target to insert, in above case edx=address of our serial.
ECX is the location for insertion, in above case it is insert at first byte.

:0048496D E8EEF5F7FF              call 00403F60			;This call for any space in our
:00484972 8B55F8                  mov edx, dword ptr [ebp-08]	;name
:00484975 8A1402                  mov dl, byte ptr [edx+eax]
:00484978 8D45F0                  lea eax, dword ptr [ebp-10]
:0048497B E820F2F7FF              call 00403BA0			;This call return eax=the char 
:00484980 8B45F0                  mov eax, dword ptr [ebp-10]	;should placed in last byte of
:00484983 50                      push eax			;code
:00484984 8B45F4                  mov eax, dword ptr [ebp-0C]
:00484987 E8ECF2F7FF              call 00403C78			;Calculate last byte location
:0048498C 8BC8                    mov ecx, eax
:0048498E 41                      inc ecx
:0048498F 8D55F4                  lea edx, dword ptr [ebp-0C]
:00484992 58                      pop eax
:00484993 E86CF5F7FF              call 00403F04			;This call insert eax from call
:00484998 8B45F4                  mov eax, dword ptr [ebp-0C]	;00403BA0 into last byte of code

The above code search for any space(20) in our name, if it does then the take the next byte
after the FIRST space and put it into last byte of our code. If it doesn't found any space, then
it will put first byte of our name into last byte of our code.
Eg: Name=abc
    code=a15335672a
    Name=abc def
    code=a87672812d
    Name=abc 123 456
    code=a-15942455d

:0048499B E8D8F2F7FF              call 00403C78
:004849A0 8BC8                    mov ecx, eax
:004849A2 D1F9                    sar ecx, 1			;ecx=length(name)>>1
:004849A4 7903                    jns 004849A9			;jump if ecx>0
:004849A6 83D100                  adc ecx, 00000000

The above code calculate the length of our name, ecx = our length of name shift right by one.


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004849A4(C)
|
:004849A9 8D55F4                  lea edx, dword ptr [ebp-0C]

* Possible StringData Ref from Code Obj ->"ClaDiTL"
                                  |
:004849AC B8804A4800              mov eax, 00484A80
:004849B1 E84EF5F7FF              call 00403F04			;This call insert "ClaDiTL" into
:004849B6 8D55EC                  lea edx, dword ptr [ebp-14]	;ecx location of code
:004849B9 8B45FC                  mov eax, dword ptr [ebp-04]
:004849BC 8B80EC010000            mov eax, dword ptr [eax+000001EC]
:004849C2 E8B9B0F9FF              call 0041FA80

The above code inserts words'ClaDiTL" into our code, it insert in the location ecx, and ecx
is our name length right shift by one.
Eg:With name=yes123
   before insertion, code=y-85638181y
   after insertion,  code=y-85ClaDiTL638181y

:004849C7 8B55EC                  mov edx, dword ptr [ebp-14]	;edx=our false key
:004849CA 8B45F4                  mov eax, dword ptr [ebp-0C]	;eax=real key
:004849CD E8B6F3F7FF              call 00403D88			;test for both key
:004849D2 7530                    jne 00484A04			;jump if not equal

The this part, it compare our fake key with the real key generated.
So we can type 'd eax' after line 4849CA to sea for the real key.


:004849D4 8D55EC                  lea edx, dword ptr [ebp-14]
:004849D7 8B45FC                  mov eax, dword ptr [ebp-04]
:004849DA 8B80EC010000            mov eax, dword ptr [eax+000001EC]
:004849E0 E89BB0F9FF              call 0041FA80
:004849E5 8B55EC                  mov edx, dword ptr [ebp-14]

* Possible StringData Ref from Code Obj ->"ClaDiTL"
                                  |
:004849E8 B8804A4800              mov eax, 00484A80
:004849ED E86EF5F7FF              call 00403F60
:004849F2 85C0                    test eax, eax
:004849F4 7E0E                    jle 00484A04
:004849F6 A114F74800              mov eax, dword ptr [0048F714]
:004849FB 8B00                    mov eax, dword ptr [eax]
:004849FD E8BA7B0000              call 0048C5BC
:00484A02 EB37                    jmp 00484A3B

The above code store our registered data into registry.

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004849D2(C), :004849F4(C)
|
:00484A04 6A00                    push 00000000
:00484A06 668B0D884A4800          mov cx, word ptr [00484A88]
:00484A0D B201                    mov dl, 01

* Possible StringData Ref from Code Obj ->"Invalid registration code!"
                                  |
:00484A0F B8944A4800              mov eax, 00484A94		;Change this code to 8B45F49090

When we trace to here, there is also a fun place to make change, we can change the :
	00484A0F B8944A4800              mov eax, 00484A94
	into:
	00484A0F 8B45F4                  mov eax, dword ptr [ebp-0C]
	00484A12 90                      nop
	00484A13 90                      nop
So that instead of display out the "Invalid registration code!", it will display out our real
key if we enter wrong key. This is beacuse from line 4849CA, we know the real key is store at
[ebp-0C]. You can try and make a patch for for it. This technique is so call 'Magic Window'.

:00484A14 E8DB7CFBFF              call 0043C6F4	
:00484A19 8B45FC                  mov eax, dword ptr [ebp-04]	
:00484A1C 8B80E0010000            mov eax, dword ptr [eax+000001E0]
:00484A22 8B10                    mov edx, dword ptr [eax]	
:00484A24 FF9294000000            call dword ptr [edx+00000094]	
:00484A2A 8B45FC                  mov eax, dword ptr [ebp-04]
:00484A2D 8B80EC010000            mov eax, dword ptr [eax+000001EC]
:00484A33 8B10                    mov edx, dword ptr [eax]
:00484A35 FF9294000000            call dword ptr [edx+00000094]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00484A02(U)
|
:00484A3B 33C0                    xor eax, eax
:00484A3D 5A                      pop edx
:00484A3E 59                      pop ecx
:00484A3F 59                      pop ecx
:00484A40 648910                  mov dword ptr fs:[eax], edx

* Possible StringData Ref from Code Obj ->"_^["
                                  |
:00484A43 68654A4800              push 00484A65

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00484A63(U)
|
:00484A48 8D45EC                  lea eax, dword ptr [ebp-14]
:00484A4B E8ACEFF7FF              call 004039FC
:00484A50 8D45F0                  lea eax, dword ptr [ebp-10]
:00484A53 BA03000000              mov edx, 00000003
:00484A58 E8C3EFF7FF              call 00403A20
:00484A5D C3                      ret

---[ OVERALL CONCLUSION OF KEY GENERATING PROCESS ]--------------------------------------------
1.code=(code*name[count1])/0x11;	//count1=counter from 0 to length of name
2.code=code*(name[count2]-0x0b);	//count2=counter from length of name to 0
3.code=((code-count1)/7)+0xf92;		//count1=length of name
4.convert code into string form.
5.insert suitable character into the head and tail of the code.
6.insert 'ClaDiTL' into suitable place of the code

---[ C-LANGUAGE CODE ]-------------------------------------------------------------------------
#include 
#include
#include 

int main(void)
  {
   long code=1;
   int count1,count2,count3;
   char name[25],reg[15];
   clrscr();
   textcolor(14);
   cprintf("    __,__\r\n");
   cprintf("   /     \\\r\n" );
   cprintf("   vvvvvvv  /|__/|\r\n");
   cprintf("      I   /O,O   |\r\n");
   cprintf("      I /_____   |      /|/|\r\n");
   cprintf("     J|/^ ^ ^ \\  |    /00  |    _//|\r\n");
   cprintf("      |^ ^ ^ ^ |W|   |/^^\\ |   /oo |\r\n");
   cprintf("       \\m___m__|_|    \\m_m_|   \\mm_|\r\n");
   textcolor(10);
   cprintf("=======================================");
   textcolor(11);
   cprintf("\r\nKeyGenerator for A Day in the Life v1.0");
   textcolor(10);
   cprintf("\r\n=======================================");
   printf("\nCracked by ");
   textcolor(14);
   cprintf("%c%c%c",0x10,0x10,0x10);
   textcolor(12);
   cprintf("Yes123");
   textcolor(14);
   cprintf("%c%c%c",0x11,0x11,0x11);
   printf(" - February 1999");
   printf("\n\nEnter register name = ");
   scanf("%[^\n]",name);
   for(count1=0;name[count1]>0;count1++)	//first loop
     code=(code*name[count1])/0x11;
   for(count2=count1-1;count2>=0;count2--)	//second loop
     code=code*(name[count2]-0x0b);
   code=((code-count1)/7)+0xf92;
   ltoa(code,reg,10);				//convert long to string
   printf("Your registration key = %c",name[0]);
   for(count2=0;reg[count2]>0;count2++);
   count2=(count2+2)>>1;
   for(count1=0;count1<(count2-2);count1++)
     printf("%c",reg[count1]);
   printf("ClaDiTL");
   for(;reg[count1]>0;count1++)
     printf("%c",reg[count1]);
   for(count1=0;name[count1]>0;count1++){
     if ((name[count1]==0x20)&&(name[count1+1]>0)){
       printf("%c",name[count1+1]);
       return;
       }
     }
   printf("%c",name[0]);
   return ;
}

---[ LAST ]-----------------------------------------------------------------------------------

I know my english expressing ability is weak, so in many place i know what's happening but i 
cann't express well and explain to you clearly. I hope you can really try it out then you can
understand more out of it. This is my first keygen tutorial and i hope you'll like it.

You can also try to trace into the call of how they insert words into string, call of how
they calculate the strings number, call of how they compare two strings, call of how they 
search for specific char in a string... Try to understand their coding, it is quite interesting 
and useful also if we met another similar call next time.

Thanks for reading my first keygen tutorial.

---[ THAT'S ALL FOLKS ]-----------------------------------------------------------------------

Yes123 '99
==========